package cmd

import (
	"fmt"
	"gitee.com/lllgo/gopkg/exec"
	"gitee.com/lllgo/gopkg/files"
	"gitee.com/lllgo/gopkg/utils"
	"gitee.com/lllgo/opsctl/pkg/conf"
	"gitee.com/lllgo/opsctl/pkg/model"
	"gitee.com/lllgo/opsctl/pkg/tools"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"os"
	"path/filepath"
	"time"
)

var (
	Execute func(args []string) error

	Register        RegisterFunc
	RegisterKit     RegisterKitFunc
	RegisterService registerServiceFunc
)

type RegisterFunc func(initConfig func(), cmd *cobra.Command, subCmd ...*cobra.Command)
type RegisterKitFunc func(initConfig func(), cmd, install, uninstall *cobra.Command, otherSubCmd ...*cobra.Command)
type registerServiceFunc func(initConfig func(), cmd, install, uninstall, start, stop *cobra.Command, otherSubCmd ...*cobra.Command)

func init() {
	var version bool

	var rootCmd = &cobra.Command{
		Use:   conf.AppName,
		Short: "运维操作工具客户端",
		Long: `运维操作工具客户端。依赖ansible、kubectl、docker
1. 二进制方式管理kubernetes集群：创建集群、添加/删除master节点、添加/删除node节点、添加/删除etcd节点、插件管理`,
		Run: func(cmd *cobra.Command, args []string) {
			if version {
				showVersion()
			}
		},
	}

	cobra.OnInitialize(initConfig)

	rootCmd.PersistentFlags().StringVarP(&conf.ConfigPath, "config", "c", "", "配置文件位置 未设置时优先读取环境变量"+conf.EnvConfig+"值，其次使用$HOME/.opsctl/config.yaml")
	rootCmd.PersistentFlags().StringVarP(&conf.InventoryPath, "inventory", "i", conf.InventoryPath, "服务器配置文件位置 未设置时优先读取环境变量"+conf.EnvInventory+"值，其次使用$HOME/.opsctl/hosts.ini")
	rootCmd.Flags().StringVarP(&conf.PluginPath, "plugin-config", "p", conf.PluginPath, "服务器配置文件位置 未设置时优先读取环境变量"+conf.EnvInventory+"值，其次使用$HOME/.opsctl/hosts.ini")
	rootCmd.PersistentFlags().StringVarP(&conf.Env, "env", "e", "", "设置操作环境")
	rootCmd.PersistentFlags().StringVarP(&conf.C.LogLevel, "log-level", "l", "", "设置操作环境")

	rootCmd.Flags().BoolVarP(&version, "version", "v", false, "显示版本信息")

	rootCmd.AddCommand(logCmd(), versionCmd(), configCmd(), tagCmd(), completionCmd())

	Execute = func(args []string) (err error) {
		rootCmd.SetArgs(args)
		msg := ""

		exec.PrintInfo()
		if err = rootCmd.Execute(); err != nil {
			msg = err.Error()
		}

		if model.HasDB() {
			return model.InsertCmd(args, msg)
		}
		return
	}

	Register = func(initConfig func(), cmd *cobra.Command, subs ...*cobra.Command) {
		if initConfig != nil {
			cobra.OnInitialize(initConfig)
		}
		if cmd != nil {
			if len(subs) > 0 {
				cmd.AddCommand(subs...)
			}
			rootCmd.AddCommand(cmd)
		}
	}

	RegisterKit = func(initConfig func(), cmd, install, uninstall *cobra.Command, otherCmd ...*cobra.Command) {
		Register(initConfig, cmd, append(otherCmd, install, uninstall)...)
	}

	RegisterService = func(initConfig func(), cmd, install, uninstall, start, stop *cobra.Command, otherCmd ...*cobra.Command) {
		RegisterKit(initConfig, cmd, install, uninstall, append(otherCmd, start, stop)...)
	}

}

func initConfig() {
	if conf.ConfigPath == "" {
		conf.ConfigPath, _ = filepath.Abs(utils.GetDefString(conf.ConfigPath, utils.GetEnv(conf.EnvConfig, conf.DefCfgFile)))
	} else {
		conf.ConfigPath, _ = filepath.Abs(conf.ConfigPath)
	}

	if err := conf.ReadAllConfig(conf.ConfigPath); err != nil {
		fmt.Println("读取配置文件错误", conf.ConfigPath, viper.ConfigFileUsed(), err)
		os.Exit(1)
	}

	if err := tools.SetAllHostsUseFile(conf.InventoryPath); err != nil {
		fmt.Println("解析hosts配置文件错误", err)
		os.Exit(1)
	}

	conf.UnmarshalConfig(&conf.C, conf.AppName)

	// 文件类型配置
	conf.C.DBDir = utils.GetDefStringWithBool(conf.C.DBDir == "", filepath.Join(conf.TmpDir(), "db"), files.Abs(conf.ConfigPath, conf.C.DBDir))
	conf.C.LogFile = utils.GetDefStringWithBool(conf.C.LogFile == "", filepath.Join(conf.TmpDir(), "opsctl.log"), files.Abs(conf.ConfigPath, conf.C.LogFile))
	conf.C.LocalDir = utils.GetDefStringWithBool(conf.C.LocalDir == "", filepath.Join(conf.TmpDir(), "middle-files"), files.Abs(conf.ConfigPath, conf.C.LocalDir))

	_ = os.Mkdir(conf.C.LocalDir, os.ModePerm)

	if conf.C.DelaySeconds == 0 {
		conf.C.DelaySeconds = 5
	}

	conf.DelayTime = time.Duration(conf.C.DelaySeconds) * time.Second

	if conf.C.LogLevel == "" {
		conf.C.LogLevel = conf.Silent.String()
	}

	_ = exec.SetLogFile(conf.C.LogFile)

	switch conf.GetLogLevel(conf.C.LogLevel) {
	case conf.Info:
		logrus.SetLevel(logrus.InfoLevel)
	case conf.Warn:
		logrus.SetLevel(logrus.WarnLevel)
	case conf.Error:
		logrus.SetLevel(logrus.ErrorLevel)
	case conf.Silent:
		logrus.SetLevel(logrus.PanicLevel)
	}

	logrus.SetFormatter(&logrus.TextFormatter{
		ForceColors:      true,
		DisableTimestamp: true,
	})

	logrus.Info("所有配置文件内容\n", viper.AllSettings())

	model.Init()
}
